package org.datascooter.cglib.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.datascooter.bundle.DSMapper;
import org.datascooter.bundle.EntityBundle;
import org.datascooter.exception.EntityNotMappedException;
import org.datascooter.impl.DataSnip;
import org.datascooter.impl.DataSnipFactory;
import org.datascooter.inface.IDataManager;
import org.datascooter.utils.LangUtils;

public abstract class AbsrtactInterceptor<T> implements MethodInterceptor {

	protected static final String EQUALS = "equals";
	protected static final String HASH_CODE = "hashCode";
	protected static final String TO_STRING = "toString";
	protected Map<Object, ValueHolder> valueMap = new HashMap<Object, ValueHolder>();
	protected Map<String, AbsrtactInterceptor<?>> childMap = new HashMap<String, AbsrtactInterceptor<?>>();
	protected T source;
	protected EntityBundle bundle;
	protected final IDataManager manager;
	protected String name;

	public AbsrtactInterceptor(IDataManager dataManager, T obj, String name) throws EntityNotMappedException, SecurityException, NoSuchMethodException {
		this.manager = dataManager;
		this.source = obj;
		this.name = name;
		bundle = DSMapper.getBundle(obj);
	}

	public Object interceptInt(Object[] args, String name2) {
		return null;
	}

	/**
	 * Flush all changes to database
	 * 
	 * @throws EntityNotMappedException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	public void flush() throws EntityNotMappedException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
		DataSnip update = DataSnipFactory.update(source);
		for (Entry<Object, ValueHolder> entry : valueMap.entrySet()) {
			if (entry.getValue().changed()) {
				String attribute = LangUtils.prepareName(entry.getKey().toString());
				update.what(attribute, entry.getValue().getValue());
			}
		}
		manager.execute(update);
		for (AbsrtactInterceptor<?> interceptor : childMap.values()) {
			interceptor.flush();
			manager.getInstanceManager().getCrossProvider().saveContent(source, interceptor.name, interceptor.source);
		}
	}

	/**
	 * Load all data from database and replace data in memory
	 */
	public void refresh() {
	}

	public Map<Object, ValueHolder> getValueMap() {
		return valueMap;
	}

	public Map<String, AbsrtactInterceptor<?>> getChildMap() {
		return childMap;
	}

	public void setChildMap(Map<String, AbsrtactInterceptor<?>> childMap) {
		this.childMap = childMap;
	}

	public T getSource() {
		return source;
	}

	@SuppressWarnings("unchecked")
	public void setSource(Object args) {
		this.source = (T) args;
	}

	@Override
	public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		return methodProxy.invokeSuper(object, args);
	}
}
